#ifndef _STDARG_H
#define _STDARG_H

typedef char *va_list;

/* Amount of space required in an argument list for an arg of type TYPE.
   TYPE may alternatively be an expression whose type is used.  

  下面给出了类型为 TYPE 的 arg 参数列表所要求的空间容量 
  TYPE 也可以是使用该类型的一个表达式   
*/

// 定义了取整后的 TYPE 类型的字节长度值。单位是 int 长度(4）的倍数。
#define __va_rounded_size(TYPE)  \
  (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

/*
第17行上的函数_builtin_saveregs(）是在gce 的库程序 libgec2.c 中定义的，用于保存寄存器。相关说明参见 gec 手册“Target Deseription Macros” 章中 “Implementing the Varargs Macros〞小节。
*/
// 下面这个宏初始化指针 AP，使其指向传给函数的可变参数表的第一个参数。
// 在第一次调用 va_arg 或 va_end 之前，必须首先调用 var_start 宏。
// 参数 LASTARG 是函数定义中最右边参数的标识符，即’...’左边的一个标识符，是最后一个指定的参数
// AP是可变参数表参数指针
// ＆(LASTARG) 用于取其地址（即其指针)，并且该指针是字符类型。加上 LASTARG 的宽度值后 AP 就是可变参数表中第一个参数的指针。该宏没有返回值。
#ifndef __sparc__
#define va_start(AP, LASTARG) 						\
 (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG) 						\
 (__builtin_saveregs (),						\
  AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif

// 下面该宏用于被调用函数完成一次正常返回。
// va_end 可以修改 AP 使其在重新调用 va_start 之前不能被使用。va_end 必须在 va_arg 读完所有的参数后再被调用。
void va_end (va_list);		/* Defined in gnulib */
#define va_end(AP)

// 下面宏用于扩展表达式使其与下一个被传递参数具有相同的类型和值。
// va_arg 宏会扩展成函数参数列表中下一个参数的类型和值。
// AP 应该与 va_start 初始化的 va_list AP 相同。
// 每次调用 va_arg 时都会修改 AP，使得下一个参数的值被返回。
// TYPE 是一个类型名。
// 在 va_start 初始化之后，第1次调用 va_arg 会返回 LASTARG 指定参数后的参数值。随后的调用会返回随后参数的值。
#define va_arg(AP, TYPE)						\
 (AP += __va_rounded_size (TYPE),					\
  *((TYPE *) (AP - __va_rounded_size (TYPE))))

#endif /* _STDARG_H */
